/* 使用node的child_process模块执行命令 */
const fs = require('fs')
const spawn = require('child_process').spawn
const strftime = require('strftime')

function execute ({ command, cwd, uid, gid, stderr, stdout }) {
  let [fd1, fd2] = createRedirectedFds(stdout, stderr, uid, gid)
  beginWrite(fd1, fd2, command)
  spawn(command, {
    shell: '/bin/bash',
    cwd: cwd,
    uid: uid,
    gid: gid,
    stdio: ['ignore', fd1, fd2],
    env: {
      PATH: '/usr/local/bin:/usr/bin'
    }
  }).on('close', (code) => endWrite(fd1, fd2, command, code))
}

function createRedirectedFds (stdout, stderr, uid, gid) {
  const fd1 = stdout ? createRedirectedFd(stdout, uid, gid) : 'ignore'
  const fd2 = stderr ? (stdout === stderr ? fd1 : createRedirectedFd(stderr, uid, gid)) : 'ignore'
  return [fd1, fd2]
}

function createRedirectedFd (path, uid, gid) {
  let fd = null
  if (fs.existsSync(path)) {
    fd = fs.openSync(path, 'a')
  } else {
    fd = fs.openSync(path, 'a')
    fs.chownSync(path, uid, gid)
  }
  return fd
}

function beginWrite (fd1, fd2, command) {
  const now = strftime('%Y-%m-%d %H:%M:%S', new Date())
  const fds = filter(fd1, fd2)
  fds.forEach(fd => {
    fs.writeSync(fd, `[${now}]新的命令执行: (${command}) {{{\n`)
  })
}

function endWrite (fd1, fd2, command, code) {
  const now = strftime('%Y-%m-%d %H:%M:%S', new Date())
  const fds = filter(fd1, fd2)
  fds.forEach(fd => {
    fs.writeSync(fd, `[${now}]命令执行结束于code ${code}: (${command}) }}}\n`)
    fs.closeSync(fd)
  })
}

function filter (fd1, fd2) {
  const fds = []
  if (fd1 !== 'ignore') {
    fds.push(fd1)
  }
  if (fd2 !== 'ignore' && fd2 !== fd1) {
    fds.push(fd2)
  }
  return fds
}

module.exports = execute
